package tasks.io.server;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import tasks.io.core.Node;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.StandardSocketOptions;
import java.nio.channels.AsynchronousChannelGroup;
import java.nio.channels.AsynchronousServerSocketChannel;
import java.util.concurrent.TimeUnit;


public class Server {
    private static final Logger log = LoggerFactory.getLogger(Server.class);
    private TioServerConfig tioServerConfig;
    private AsynchronousServerSocketChannel asynchronousServerSocketChannel;
    private AsynchronousChannelGroup asynchronousChannelGroup = null;
    private Node serverNode;
    private boolean isWaitingStop = false;
    private final boolean checkLastVersion = true;

    /**
     * @param tioServerConfig
     * @author tanyaowu
     * 2017年1月2日 下午5:53:06
     */
    public Server(TioServerConfig tioServerConfig) {
        super();
        this.tioServerConfig = tioServerConfig;
    }

    /**
     * @return the tioServerConfig
     */
    public TioServerConfig getTioServerConfig() {
        return tioServerConfig;
    }

    /**
     * @return the serverNode
     */
    public Node getServerNode() {
        return serverNode;
    }

    /**
     * @return the serverSocketChannel
     */
    public AsynchronousServerSocketChannel getAsynchronousServerSocketChannel() {
        return asynchronousServerSocketChannel;
    }

    /**
     * @return the isWaitingStop
     */
    public boolean isWaitingStop() {
        return isWaitingStop;
    }

    /**
     * @param tioServerConfig the tioServerConfig to set
     */
    public void setTioServerConfig(TioServerConfig tioServerConfig) {
        this.tioServerConfig = tioServerConfig;
    }

    /**
     * @param isWaitingStop the isWaitingStop to set
     */
    public void setWaitingStop(boolean isWaitingStop) {
        this.isWaitingStop = isWaitingStop;
    }

    public void start(String serverIp, int serverPort) throws IOException {
        long start = System.currentTimeMillis();
        this.serverNode = new Node(serverIp, serverPort);
        asynchronousChannelGroup = AsynchronousChannelGroup.withThreadPool(tioServerConfig.groupExecutor);
        asynchronousServerSocketChannel = AsynchronousServerSocketChannel.open(asynchronousChannelGroup);

        asynchronousServerSocketChannel.setOption(StandardSocketOptions.SO_REUSEADDR, true);
        asynchronousServerSocketChannel.setOption(StandardSocketOptions.SO_RCVBUF, 64 * 1024);

        InetSocketAddress inetSocketAddress = null;

        if (serverIp == null) {
            inetSocketAddress = new InetSocketAddress(serverPort);
        } else {
            inetSocketAddress = new InetSocketAddress(serverIp, serverPort);
        }

        asynchronousServerSocketChannel.bind(inetSocketAddress, 0);

        AcceptCompletionHandler acceptCompletionHandler = tioServerConfig.getAcceptCompletionHandler();
        asynchronousServerSocketChannel.accept(this, acceptCompletionHandler);

        tioServerConfig.startTime = System.currentTimeMillis();


    }

    /**
     * @return
     * @author tanyaowu
     */
    public boolean stop() {
        isWaitingStop = true;
        boolean ret = true;

        try {
            asynchronousChannelGroup.shutdownNow();
        } catch (Exception e) {
            log.error("channelGroup.shutdownNow()时报错", e);
        }

        try {
            asynchronousServerSocketChannel.close();
        } catch (Exception e1) {
            log.error("serverSocketChannel.close()时报错", e1);
        }

        try {
            tioServerConfig.groupExecutor.shutdown();
        } catch (Exception e1) {
            log.error(e1.toString(), e1);
        }
        try {
            tioServerConfig.tioExecutor.shutdown();
        } catch (Exception e1) {
            log.error(e1.toString(), e1);
        }

        tioServerConfig.setStopped(true);
        try {
            ret = ret && tioServerConfig.groupExecutor.awaitTermination(6000, TimeUnit.SECONDS);
            ret = ret && tioServerConfig.tioExecutor.awaitTermination(6000, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            log.error(e.getLocalizedMessage(), e);
        }

        log.info(this.serverNode + " stopped");
        return ret;
    }

    public boolean isCheckLastVersion() {
        return checkLastVersion;
    }

    public void setCheckLastVersion(boolean checkLastVersion) {
        log.debug("community edition is no longer supported");
        //		this.checkLastVersion = checkLastVersion;
    }
}
